package xxl.robotlegs.extensions.matching.impl 
{
	import flash.utils.getQualifiedClassName;
	import xxl.robotlegs.extensions.matching.api.ITypeFilter;
	/**
	 * ...
	 * @author XXL
	 */
	public class TypeFilter implements ITypeFilter
	{
		protected var _allOfTypes:Vector.<Class>;
		protected var _anyOfTypes:Vector.<Class>;
		protected var _noneOfTypes:Vector.<Class>;
		protected var _descriptor:String;
		
		public function TypeFilter(allOf:Vector.<Class>, anyOf:Vector.<Class>, noneOf:Vector.<Class>) 
		{
			if (!allOf || !anyOf || !noneOf)
			{
				throw new ArgumentError("参数不能为空");
			}
			_allOfTypes = allOf;
			_anyOfTypes = anyOf;
			_noneOfTypes = noneOf;
		}
		
		public function toString():String
		{
			return "TypeFilter：" + descriptor;
		}
		
		protected function createDescriptor():String
		{
			const allOf_FCQNs:Vector.<String> = alphabetiseCaseInsensitiveFCQNs(allOfTypes);
			const anyOf_FCQNs:Vector.<String> = alphabetiseCaseInsensitiveFCQNs(anyOfTypes);
			const noneOf_FQCNs:Vector.<String> = alphabetiseCaseInsensitiveFCQNs(noneOfTypes);
			return "all of: " + allOf_FCQNs.toString()
				+ ", any of: " + anyOf_FCQNs.toString()
				+ ", none of: " + noneOf_FQCNs.toString();
		}
		
		protected function alphabetiseCaseInsensitiveFCQNs(classVector:Vector.<Class>):Vector.<String>
		{
			const allFCQNs:Vector.<String> = new Vector.<String>;
			const len:int = classVector.length;
			for (var i:int = 0; i < len; i++) 
			{
				const fqcn:String = getQualifiedClassName(classVector[i]);
				allFCQNs.push(fqcn);
			}
			allFCQNs.sort(stringSort);
			return allFCQNs;
		}
		
		protected function stringSort(item1:String, item2:String):int
		{
			if (item1 < item2)
			{
				return 1;
			}
			return -1;
		}
		
		/* INTERFACE xxl.robotlegs.extensions.matching.api.ITypeFilter */
		
		public function get allOfTypes():Vector.<Class> 
		{
			return _allOfTypes;
		}
		
		public function get anyOfTypes():Vector.<Class> 
		{
			return _anyOfTypes;
		}
		
		public function get noneOfTypes():Vector.<Class> 
		{
			return _noneOfTypes;
		}
		
		public function get descriptor():String 
		{
			return _descriptor ||= createDescriptor();
		}
		
		public function matches(item:*):Boolean 
		{
			var i:int;
			for (i = _allOfTypes.length; i--; )
			{
				if (!(item is _allOfTypes[i]))
				{
					return false;
				}
			}
			for (i = _noneOfTypes.length; i--; )
			{
				if (item is _noneOfTypes[i])
				{
					return false;
				}
			}
			if (_anyOfTypes.length == 0 && (_allOfTypes.length > 0 || _noneOfTypes.length > 0))
			{
				return true;
			}
			for (i = _anyOfTypes.length; i--; )
			{
				if (item is _anyOfTypes[i])
				{
					return true;
				}
			}
			return false;
		}
		
	}

}